跳到主要内容

从spring HttpStatusCode源码聊聊jdk17新增的sealed关键字

背景

最近在开发的时候看到spring中的HttpStatusCode出现了一个以前低版本jdk没用到的关键字sealed

所以打算来学习研究下这个新语法

何时引进

sealed关键字在jdk15jdk16都是作为预览特性出现

直到jdk17才被正式引入

作用

sealed关键字主要是用于通过permits关键字明确指定允许继承的子类列表

我们先看看在没有sealed关键字我们是如何限制类的继承

final关键字

如果一个类加上final关键字,则完全禁止类被继承

public final class XiaoZou {}

现在类的访问权限

比如我们不将类设置为public,使用默认的私有权限

package com.xiaozou;

class Animal {}

这样仅同包才能继承Animal

package com.xiaozou;

public class Dog extends Animal {}

缺点

我们可以看到通过上面的几种方式都没有办法只管切灵活的限制类的子类的实现。

比如我想要某个类,仅只能我自定义的几个类去实现。

我的这几个继承类可能是夸包,用上面的方式都不灵活。

那我们看看如何使用sealed关键字进行实现

sealed关键字使用

继承限制

比如我这里有一个父类Car 我想要仅MiniCarBigCar能继承

那么如何实现这个需求呢?

使用sealed + permits关键字就很简单了

public sealed class Car permits MiniCar, BigCar { }
public final class MiniCar extends Car { } 
public final class BigCar extends Car { } 

sealed关键字使用说明

  1. 如果使用permits限制了MiniCarBigCar类的继承。则MiniCarBigCar必须继承Car,否则编译报错

  2. MiniCarBigCar必须声明为final 否则也会编译报错

实现的限制

不仅仅是对类的继承进行限制,也可以对接口的实现进行限制。

这里我们就不自己延时了,直接看springHttpStatusCode源码中的应用

spring中HttpStatusCode permits的应用

public sealed interface HttpStatusCode extends Serializable permits DefaultHttpStatusCode, HttpStatus {}

可以看到HttpStatusCode接口限制了其实现类只能是DefaultHttpStatusCodeHttpStatus

final class DefaultHttpStatusCode implements HttpStatusCode, Comparable<HttpStatusCode>, Serializable {}
public enum HttpStatus implements HttpStatusCode {}

DefaultHttpStatusCodeHttpStatus也确实实现了HttpStatusCode接口

同时DefaultHttpStatusCode也强制被声明成了final

HttpStatus因为是枚举所以无需声明成final

如果我们自定义一个类去实现HttpStatusCode接口就会发现编译报错

alt text

总结

jdk17引入sealed关键字主要有如下几个优势

  1. 精确控制继承(实现)关系: 通过permits明确列出允许继承(实现)的子类,避免意外的类扩展

  2. 增强代码可维护性: 明确的子类(实现)列表使代码结构更清晰,便于后续扩展或重构

  3. 模式匹配处理更安全

像上面Car的例子我们可以直接使用模式匹配,安全处理所有可能的子类

    public static void processCar(Car car) {
switch (car) {
case BigCar bigCar -> System.out.println("BigCar");
case MiniCar miniCar -> System.out.println("MiniCar");
case null -> System.out.println("Null car");
default -> System.out.println("Unknown car type");
}
}